home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / tio.c < prev    next >
C/C++ Source or Header  |  1994-01-10  |  27KB  |  1,257 lines

  1. /* tio.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains terminal I/O functions */
  12.  
  13. #include "config.h"
  14. #include <string.h>
  15. #include "vi.h"
  16. #include "ctype.h"
  17. extern char *printable();
  18.  
  19. static int showmsg P_((void));
  20.  
  21. /* This function reads in a line from the terminal.  It simulates the normal
  22.  * line editing for cooked input, with support for backspace, ^U, and ^V.
  23.  *
  24.  * Support for ^W and ^P added by sdw, Nov. 1993.
  25.  *
  26.  * It tries to hide the extra ^O that a "visual" map inserts before each
  27.  * character.  When it reads a ^O, it discards it and reads the next character.
  28.  * Then only exception is after a ^V which itself was not preceded by a ^O, the
  29.  * character immediately following the ^V is accepted even if it is a ^O.
  30.  *
  31.  * Eventually I hope to make it use ^O to access a history of previously
  32.  * entered commands.  ^Ok to move back, ^Ol to move forward, etc.  This way,
  33.  * the standard arrow key mappings can be used to access history easily, and
  34.  * users who don't have the benefit of arrow keys will still be able to use
  35.  * history.  But that hasn't happened yet.
  36.  */
  37. int vgets(prompt, buf, bsize)
  38.     int    prompt;    /* the prompt character, or '\0' for none */
  39.     char    *buf;    /* buffer into which the string is read */
  40.     int    bsize;    /* size of the buffer */
  41. {
  42.     int    len;    /* how much we've read so far */
  43.     int    ch;    /* a character from the user */
  44.     int    quoted;    /* is the next char quoted? */
  45.     int    tab;    /* column position of cursor */
  46.     char    widths[132];    /* widths of characters */
  47.     int    word;    /* index of first letter of word */
  48. #ifndef NO_DIGRAPH
  49.     int    erased;    /* 0, or first char of a digraph */
  50. #endif
  51. #ifndef NO_EXTENSIONS
  52.     int    ctrlO;    /* boolean: was last character ^O ? */
  53. #endif
  54. #if 1 /* [sdw] */
  55.     int    cbsize;    /* size of cut buffer to be pasted */
  56. #endif
  57.  
  58.     /* show the prompt */
  59.     move(LINES - 1, 0);
  60.     tab = 0;
  61.     if (prompt)
  62.     {
  63.         addch(prompt);
  64.         tab = 1;
  65.     }
  66.     clrtoeol();
  67.     refresh();
  68.  
  69.     /* read in the line */
  70. #ifndef NO_DIGRAPH
  71.     erased =
  72. #endif
  73. #ifndef NO_EXTENSIONS
  74.     ctrlO =
  75. #endif
  76.     quoted = len = 0;
  77.     for (;;)
  78.     {
  79. #ifndef NO_ABBR
  80.         if (quoted || mode == MODE_EX)
  81.         {
  82.             ch = getkey(0);
  83.         }
  84.         else
  85.         {
  86.             /* maybe expand an abbreviation while getting key */
  87.             ch = getabkey(WHEN_EX, buf, len);
  88.         }
  89. #else
  90.         ch = getkey(0);
  91. #endif
  92. #ifndef NO_EXTENSIONS
  93.         if (ctrlO || !quoted && ch == ctrl('O'))
  94.         {
  95.             ch = getkey(quoted ? 0 : WHEN_EX);
  96.             if (ch == ctrl('V'))
  97.             {
  98.                 ctrlO = TRUE;
  99.             }
  100.         }
  101. #endif
  102.  
  103.         /* some special conversions */
  104. #if 0
  105.         if (ch == ctrl('D') && len == 0)
  106.             ch = ctrl('[');
  107. #endif
  108. #ifndef NO_DIGRAPH
  109.         if (*o_digraph && erased != 0 && ch != '\b')
  110.         {
  111.             ch = digraph(erased, ch);
  112.             erased = 0;
  113.         }
  114. #endif
  115.  
  116.         /* inhibit detection of special chars (except ^J) after a ^V */
  117.         if (quoted && ch != '\n')
  118.         {
  119.             ch |= 256;
  120.         }
  121.  
  122.         /* process the character */
  123.         switch(ch)
  124.         {
  125.           case ctrl('V'):
  126.             qaddch('^');
  127.             qaddch('\b');
  128.             quoted = TRUE;
  129.             break;
  130.  
  131.           case ctrl('D'):
  132.             return -1;
  133.  
  134.           case ctrl('['):
  135.           case '\n':
  136. #if OSK
  137.           case '\l':
  138. #else
  139.           case '\r':
  140. #endif
  141.             clrtoeol();
  142.             goto BreakBreak;
  143.  
  144. #ifndef CRUNCH
  145.           case ctrl('U'):
  146.             while (len > 0)
  147.             {
  148.                 len--;
  149.                 while (widths[len]-- > 0)
  150.                 {
  151.                     qaddch('\b');
  152.                     qaddch(' ');
  153.                     qaddch('\b');
  154.                 }
  155.             }
  156.             break;
  157.  
  158.           /* [sdw] -- verbose but functional... */
  159.           /* erase over previous Word */
  160.           case ctrl('W'):
  161.             if (len == 0)
  162.             {
  163.                 return -1;
  164.             }
  165.             while (len > 0
  166.                 && (buf[len-1] == ' ' || buf[len-1] == '\t'))
  167.             {
  168.                 len--;
  169. #  ifndef NO_DIGRAPH
  170.                 erased = buf[len];
  171. #  endif
  172.                 for (ch = widths[len]; ch > 0; ch--)
  173.                     addch('\b');
  174.                 tab -= widths[len];
  175.             }
  176.             while (len > 0
  177.                 && buf[len-1] != ' ' && buf[len-1] != '\t')
  178.             {
  179.                 len--;
  180. #  ifndef NO_DIGRAPH
  181.                 erased = buf[len];
  182. #  endif
  183.                 for (ch = widths[len]; ch > 0; ch--)
  184.                     addch('\b');
  185.                 tab -= widths[len];
  186.             }
  187.             if (mode == MODE_EX)
  188.             {
  189.                 clrtoeol();
  190.             }
  191.             break;
  192. #endif
  193.  
  194.           case '\b':
  195.             if (len > 0)
  196.             {
  197.                 len--;
  198. #ifndef NO_DIGRAPH
  199.                 erased = buf[len];
  200. #endif
  201.                 for (ch = widths[len]; ch > 0; ch--)
  202.                     addch('\b');
  203.                 if (mode == MODE_EX)
  204.                 {
  205.                     clrtoeol();
  206.                 }
  207.                 tab -= widths[len];
  208.             }
  209.             else
  210.             {
  211.                 return -1;
  212.             }
  213.             break;
  214.  
  215. #if 1 /* [sdw] */
  216.           /* paste in contents of anonymous buffer */
  217.           case ctrl('P'):
  218.             cbsize = cb2str(0, tmpblk.c, BLKSIZE);
  219.             if (cbsize > 0 && cbsize != BLKSIZE)
  220.             {
  221.                 execmap(0, tmpblk.c, FALSE);
  222.             }
  223.             break;
  224. #endif
  225.  
  226.           default:
  227.             /* strip off quotation bit */
  228.             if (ch & 256)
  229.             {
  230.                 ch &= ~256;
  231.                 qaddch(' ');
  232.                 qaddch('\b');
  233.             }
  234.  
  235.             /* add & echo the char */
  236.             if (len < bsize - 1)
  237.             {
  238.                 if (ch == '\t' && !quoted)
  239.                 {
  240.                     widths[len] = *o_tabstop - (tab % *o_tabstop);
  241.                     addstr("        " + 8 - widths[len]);
  242.                     tab += widths[len];
  243.                 }
  244.                 else if (ch > 0 && ch < ' ') /* > 0 by GB */
  245.                 {
  246.                     addch('^');
  247.                     addch(ch + '@');
  248.                     widths[len] = 2;
  249.                     tab += 2;
  250.                 }
  251.                 else if (ch == '\177')
  252.                 {
  253.                     addch('^');
  254.                     addch('?');
  255.                     widths[len] = 2;
  256.                     tab += 2;
  257.                 }
  258.                 else
  259.                 {
  260.                     addch(ch);
  261.                     widths[len] = 1;
  262.                     tab++;
  263.                 }
  264.                 buf[len++] = ch;
  265.             }
  266.             else
  267.             {
  268.                 beep();
  269.             }
  270. #ifndef NO_EXTENSIONS
  271.             ctrlO =
  272. #endif
  273.             quoted = FALSE;
  274.         }
  275.     }
  276. BreakBreak:
  277.     refresh();
  278.     buf[len] = '\0';
  279.     return len;
  280. }
  281.  
  282.  
  283. static int    manymsgs; /* This variable keeps msgs from overwriting each other */
  284. static char    pmsg[80]; /* previous message (waiting to be displayed) */
  285.  
  286.  
  287. static int showmsg()
  288. {
  289.     /* if there is no message to show, then don't */
  290.     if (!manymsgs)
  291.         return FALSE;
  292.  
  293.     /* display the message */
  294.     move(LINES - 1, 0);
  295.     if (*pmsg)
  296.     {
  297.         standout();
  298.         qaddch(' ');
  299.         qaddstr(pmsg);
  300.         qaddch(' ');
  301.         standend();
  302.     }
  303.     clrtoeol();
  304.  
  305.     manymsgs = FALSE;
  306.     return TRUE;
  307. }
  308.  
  309.  
  310. void endmsgs()
  311. {
  312.     if (manymsgs)
  313.     {
  314.         showmsg();
  315.         addch('\n');
  316.     }
  317. }
  318.  
  319. /* Write a message in an appropriate way.  This should really be a varargs
  320.  * function, but there is no such thing as vwprintw.  Hack!!!
  321.  *
  322.  * In MODE_EX or MODE_COLON, the message is written immediately, with a
  323.  * newline at the end.
  324.  *
  325.  * In MODE_VI, the message is stored in a character buffer.  It is not
  326.  * displayed until getkey() is called.  msg() will call getkey() itself,
  327.  * if necessary, to prevent messages from being lost.
  328.  *
  329.  * msg("")        - clears the message line
  330.  * msg("%s %d", ...)    - does a printf onto the message line
  331.  */
  332. #if NEWSTYLE
  333. void msg (char *fmt, ...)
  334. {
  335.     va_list    ap;
  336.     va_start (ap, fmt);
  337. #else
  338. void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
  339.     char    *fmt;
  340.     long    arg1, arg2, arg3, arg4, arg5, arg6, arg7;
  341. {
  342. #endif
  343.     if (mode != MODE_VI)
  344.     {
  345. #if NEWSTYLE
  346.         vsprintf (pmsg, fmt, ap);
  347. #else
  348.         sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  349. #endif
  350.         qaddstr(pmsg);
  351.         addch('\n');
  352.         exrefresh();
  353.     }
  354.     else
  355.     {
  356.         /* wait for keypress between consecutive msgs */
  357.         if (manymsgs)
  358.         {
  359.             getkey(WHEN_MSG);
  360.         }
  361.  
  362.         /* real message */
  363. #if NEWSTYLE
  364.         vsprintf (pmsg, fmt, ap);
  365. #else
  366.         sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  367. #endif
  368.         if (*fmt)
  369.         {
  370.             manymsgs = TRUE;
  371.         }
  372.     }
  373. #ifdef    __STDC__
  374.     va_end (ap);
  375. #endif
  376. }
  377.  
  378.  
  379. /* This function calls refresh() if the option exrefresh is set */
  380. void exrefresh()
  381. {
  382.     char    *scan;
  383.  
  384.     /* If this ex command wrote ANYTHING set exwrote so vi's  :  command
  385.      * can tell that it must wait for a user keystroke before redrawing.
  386.      */
  387.     for (scan=kbuf; scan<stdscr; scan++)
  388.         if (*scan == '\n')
  389.             exwrote = TRUE;
  390.  
  391.     /* now we do the refresh thing */
  392.     if (*o_exrefresh)
  393.     {
  394.         refresh();
  395.     }
  396.     else
  397.     {
  398.         wqrefresh();
  399.     }
  400.     if (mode != MODE_VI)
  401.     {
  402.         manymsgs = FALSE;
  403.     }
  404. }
  405.  
  406.  
  407. /* This structure is used to store maps and abbreviations.  The distinction
  408.  * between them is that maps are stored in the list referenced by the "maps"
  409.  * pointer, while abbreviations are referenced by the "abbrs" pointer.
  410.  */
  411. typedef struct _map
  412. {
  413.     struct _map    *next;    /* another abbreviation */
  414.     short        len;    /* length of the "rawin" characters */
  415.     short        flags;    /* various flags */
  416.     char        *label;    /* label of the map/abbr, or NULL */
  417.     char        *rawin;    /* the "rawin" characters */
  418.     char        *cooked;/* the "cooked" characters */
  419. } MAP;
  420.  
  421. static char    keybuf[KEYBUFSIZE];
  422. static int    cend;    /* end of input characters